////////////////////////////////////////////////////////////////////////////////
//
// $Id$ 
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// 
// This software consists of voluntary contributions is licensed under the 
// MIT <http://www.opensource.org/licenses/mit-license.php>. 
// 
// 
// Portuguese Translation
// 
// ESTE SOFTWARE É FORNECIDO “COMO ESTÁ”, SEM GARANTIAS DE QUALQUER ESPÉCIE, 
// EXPRESSAS OU TÁCITAS, INCLUINDO SEM LIMITAÇÕES, QUAISQUER GARANTIA DE COMERCIABILIDADE, 
// DE ADEQUAÇÃO A FINALIDADES ESPECÍFICAS OU DE NÃO VIOLAÇÃO A DIREITOS DE TERCEIROS. 
// EM NENHUMA HIPÓTESE OS AUTORES OU TITULARES DOS DIREITOS AUTORAIS SERÃO RESPONSÁVEIS 
// POR QUAISQUER RECLAMAÇÕES E/OU INDENIZAÇÕES POR DANOS OU POR OUTROS MOTIVOS, 
// SEJAM ESSES DERIVADOS DE OBRIGAÇÕES CONTRATUAIS OU DE DECISÕES JUDICIAIS, 
// ILÍCITOS CIVIS OU OUTROS MOTIVOS, OS QUAIS VENHAM A OCORRER EM CONSEQÜÊNCIA 
// OU EM RELAÇÃO AO SOFTWARE , A SEU USO OU OUTRA FORMA DE NEGOCIAÇÃO/UTILIZAÇÃO. 
// 
// Esse software consiste de contribuições voluntárias e está sobre a licença
// MIT <http://www.opensource.org/licenses/mit-license.php>.
// 
////////////////////////////////////////////////////////////////////////////////

package br.mcaslib.common
{
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.geom.Point;
	
	import mx.collections.IList;
	import mx.controls.ComboBase;
	import mx.controls.DateField;
	import mx.controls.advancedDataGridClasses.AdvancedDataGridColumn;
	import mx.controls.dataGridClasses.DataGridColumn;
	import mx.core.IFlexDisplayObject;
	import mx.core.UIComponent;
	import mx.effects.Effect;
	import mx.effects.Fade;
	import mx.effects.WipeDown;
	import mx.effects.WipeUp;
	import mx.formatters.CurrencyFormatter;
	import mx.formatters.DateFormatter;
	import mx.formatters.NumberFormatter;
	import mx.managers.PopUpManager;
	import mx.resources.IResourceManager;
	import mx.resources.ResourceManager;
	import mx.utils.UIDUtil;
	
	import spark.components.ComboBox;

	public class Util
	{
		//--------------------------------------------------------------------------
		//
		//  Constructor
		//
		//--------------------------------------------------------------------------
		
		public function Util() {
		}
		
		//--------------------------------------------------------------------------
		//
		//  Constants
		//
		//--------------------------------------------------------------------------
		
		public static const DATE_FORMAT:String="DD/MM/YYYY";
		public static const DATETIME_SHORT_FORMAT:String="DD/MM/YYYY JJ:NN";
		public static const DATETIME_LONG_FORMAT:String="DD/MM/YYYY JJ:NN:SS, EEEE";
		
		//--------------------------------------------------------------------------
		//
		//  Properties
		//
		//--------------------------------------------------------------------------
		
		//--------------------------------------------------------------------------
		//
		//  Static Methods
		//
		//--------------------------------------------------------------------------
		
		public static function dateFormatter( d: Date ): String {
			//var rm: IResourceManager = ResourceManager.getInstance();
			//var symbol: String = rm.getString( "SharedResources", "currencySymbol" );
			var dateFormatter:DateFormatter = new DateFormatter();
			dateFormatter.formatString = Util.DATE_FORMAT;
			return dateFormatter.format( d );
		}
		
		public static function dateTimeFormatter( d: Date ): String {
			var dateFormatter:DateFormatter = new DateFormatter();
			dateFormatter.formatString = Util.DATETIME_SHORT_FORMAT;
			return dateFormatter.format( d );
		}
		
		public static function dateTimeLongFormatter( d: Date ): String {
			var dateFormatter:DateFormatter = new DateFormatter();
			dateFormatter.formatString = Util.DATETIME_LONG_FORMAT;
			return dateFormatter.format( d );
		}
		
		/**
		 * Format a number with the same rules of currency but without the symbol currency
		 */		
		public static function numberCurrencyFormatter( n: Number ): String {
			var numberFormatter:NumberFormatter = new NumberFormatter();
			var rm:IResourceManager = ResourceManager.getInstance();
			var p: int = rm.getInt( "formatters", "currencyFormatterPrecision" );
			p = (p<0) ? 2 : p;
			numberFormatter.precision = p;
			numberFormatter.rounding = "nearest";
			numberFormatter.useThousandsSeparator = true;
			return numberFormatter.format( n );
		}
		
		public static function currencyFormatter( n: Number ): String {
			var numberFormatter:CurrencyFormatter = new CurrencyFormatter();
			numberFormatter.precision = 2;
			numberFormatter.rounding = "nearest";
			numberFormatter.useThousandsSeparator = true;
			return numberFormatter.format( n );
		}
		
		public static function numberFormatter( n: Number ): String {
			var numberFormatter:NumberFormatter = new NumberFormatter();
			numberFormatter.precision = 2;
			numberFormatter.useThousandsSeparator = true;
			return numberFormatter.format( n );
		}
		
		public static function integerFormatter( n: Number ): String {
			var numberFormatter:NumberFormatter = new NumberFormatter();
			numberFormatter.precision = 0;
			numberFormatter.useThousandsSeparator = true;
			return numberFormatter.format( n );
		}
		
		
		/**
		 * Parse string to float. This function differ the official parseFloat function
		 * in using locale number locale settings correctly. For example: If you pass a 
		 * string with thousands separator the official parseFloat return impredictable
		 * result.
		 */
		public static function parseStringToNumber( s: String ): Number {
			if( s != "" ) {
				var reg:RegExp;
				var sNumber:String;
				var rm: IResourceManager = ResourceManager.getInstance();
				var t: String = rm.getString( "SharedResources", "thousandsSeparatorFrom" )
				var d: String = rm.getString( "SharedResources", "decimalSeparatorFrom" )
				
				if( t == "." ) t = "\\" + t;
				if( d == "." ) d = "\\" + d;
				reg = new RegExp( t, "g" );
				sNumber = s.replace( reg, "" );
				reg = new RegExp( d, "g" );
				sNumber = sNumber.replace( reg, "." );
				
				var n: Number = parseFloat( sNumber );
				return n;
			}
			return NaN;
		}
		
		/**
		 * A US string is a string with no thousand separator and "." for
		 * for decimal separator.
		 */
		public static function parseStringUSToNumber( s: String ): Number {
			var n: Number;
			if( s ) {
				var rm: IResourceManager = ResourceManager.getInstance();
				var t: String = rm.getString( "SharedResources", "thousandsSeparatorFrom" )
				var reg: RegExp = new RegExp( "\\.", "g" );
				var sNumber: String = s.replace( reg, t );
				n = parseFloat( sNumber );
			}
			return n;
		}
		
		public static function currencyToNumber ( s:String ):Number {
			var rm: IResourceManager = ResourceManager.getInstance();
			var symbol: String = rm.getString( "SharedResources", "currencySymbol" );
			var n:Number = Util.parseStringToNumber( s.replace(symbol,'') );
			return n;
		}

		/**
		 * Use it for labelFunction propertie of AdvancedDataGridColumn
		 */
		public static function advancedDataGridFromFieldToLabel( item:Object, column:AdvancedDataGridColumn ): String {
			return Util.dataFieldToLabel( item, column.dataField );
		}
		
		/**
		 * Use it for labelFunction propertie of DataGridColumn
		 */
		public static function dataGridFromFieldToLabel( item: Object, column:DataGridColumn ): String {
			return Util.dataFieldToLabel( item, column.dataField );
		}
		
		/**
		 * Convert an model item to label data.
		 * The dataField property of column should be filled with correct path
		 * on data model item object. The type of this property can be described
		 * as a suffix string like ':<type>'
		 */ 
		public static function dataFieldToLabel( item:Object, fieldPath:String ):String {
			var type: String = Util.dataTypeFromObjFieldPath( fieldPath );
			var item: Object = Util.dataValueFromObjFieldPath( item, fieldPath );

			if( item != null ) {
				var value: String;
				switch( type ) {
					case 'DATE':
						value = Util.dateFormatter( item as Date );
						break;
					case 'DATETIME':
						value = Util.dateTimeFormatter( item as Date );
						break;
					case 'BOOLEAN':
						if( item ) {
							value = "SIM";
						} else {
							value = "NÃO";
						}
						break;
					case 'STRING':
						value = item.toString();
						break;
					case 'CURRENCY':
						value = Util.currencyFormatter( parseFloat(item.toString()) );
						break;
					case 'PERCENT':
						value = Util.numberCurrencyFormatter( parseFloat(item.toString()) ) + "%";
						break;
					case 'NUMBER':
						value = Util.numberFormatter( parseFloat(item.toString()) );
						break;
					case 'INTEGER':
						value = Util.integerFormatter( parseFloat(item.toString()) );
						break;
					default:
						value = item.toString();
				}
			} else {
				value = "";	
			}
			
			return value;
		}
		
		public static function dataValueFromObjFieldPath( obj:Object, fieldPath:String ):Object {
			var pathType: Array = fieldPath.split( ':' );
			var pathModel: String = pathType[0];
			var properties: Array = pathModel.split( '.' );
			for each( var property: String in properties ) {
				if( obj && obj.hasOwnProperty( property ) ) {
					obj = obj[property];
				} else {
					obj = null;
					trace( "There is no '"+property+"' in obj: "+obj ); 
					break; 
				}
				
				if( obj == null ) {
					break;
				}
			}
			return obj;
		}

		public static function dataTypeFromObjFieldPath( fieldPath:String ):String {
			var type: String = "STRING";
			var pathType: Array = fieldPath.split( ':' );
			if( pathType.length > 1 ) {
				type = pathType[1];
			}
			return type.toUpperCase();
		}

		/**
		 * Convert an model item to label data.
		 * The dataField property of column should be filled with correct path
		 * on data model item object. The type of this property can be described
		 * as a suffix string like ':<type>'
		 */ 
		public static function dataFieldCompareFunction( fieldPath:String ):Function {
			var sortFunction:Function;
			var type:String = Util.dataTypeFromObjFieldPath( fieldPath );
			switch( type ) {
				case 'DATE':
				case 'DATETIME':
					sortFunction = function ( obj1:Object, obj2:Object ):int {
						var r:int;
						var d1:Date = Util.dataValueFromObjFieldPath( obj1, fieldPath ) as Date;
						var d2:Date = Util.dataValueFromObjFieldPath( obj2, fieldPath ) as Date;
						if( d1.time > d2.time ) {
							r = 1;
						} else if( d1.time < d2.time ) {
							r = -1;
						} else {
							r = 0;
						}
						return r;
					} 
					break;
				case 'BOOLEAN':
					sortFunction = function ( obj1:Object, obj2:Object ):int {
						var r:int;
						var d1:Boolean = Util.dataValueFromObjFieldPath( obj1, fieldPath ) as Boolean;
						var d2:Boolean = Util.dataValueFromObjFieldPath( obj2, fieldPath ) as Boolean;
						if( d1 > d2 ) {
							r = 1;
						} else if( d1 < d2 ) {
							r = -1;
						} else {
							r = 0;
						}
						return r;
					} 
					break;
				case 'STRING':
					sortFunction = function ( obj1:Object, obj2:Object ):int {
						var r:int;
						var d1:String = Util.dataValueFromObjFieldPath( obj1, fieldPath ) as String;
						var d2:String = Util.dataValueFromObjFieldPath( obj2, fieldPath ) as String;
						if( d1 == null ) d1 = "";
						if( d2 == null ) d2 = "";
						if( d1 > d2 ) {
							r = 1;
						} else if( d1 < d2 ) {
							r = -1;
						} else {
							r = 0;
						}
						return r;
					} 
					break;
				case 'CURRENCY':
				case 'PERCENT':
				case 'NUMBER':
					sortFunction = function ( obj1:Object, obj2:Object ):int {
						var r:int;
						var d1:Number = Util.dataValueFromObjFieldPath( obj1, fieldPath ) as Number;
						var d2:Number = Util.dataValueFromObjFieldPath( obj2, fieldPath ) as Number;
						if( d1 > d2 ) {
							r = 1;
						} else if( d1 < d2 ) {
							r = -1;
						} else {
							r = 0;
						}
						return r;
					} 
					break;
				default:
					throw new String( "Type '" + type + "' não conhecido para fazer sort" );
			}
			return sortFunction;
		}

		static public function underScoreToCammelCase( s: String ): String {
			var pattern: RegExp = /(^|_)(.)/g;
			return s.replace( pattern, 
				function (... args): String {
					return String(args[2]).toUpperCase();
				}
			);
		}
		
		static public function cammelCaseToUnderScore( s: String ): String {
			var pattern: RegExp = /([A-Z])/g;
			var result: String = s.replace( pattern, 
				function (... args): String {
					return "_" + String(args[1]).toLowerCase();
				}
			);
			if( result.substr( 0, 1 ) == "_" ) {
				result = result.substr( 1 );
			}
			return result;
		}

		/**
		 * Search a object by an id property in collection;
		 * 
		 * All objects in collection should have an unique id property
		 */
		public static function searchObjectIdInCollection(collection:IList, id:*, key:String='id'):Object {
			for each (var item:Object in collection) {
				if( item.hasOwnProperty(key) && item[key] == id ) {
					return item;
				}
			}
			return null;
		}
		
		
		/**
		 * Search a object index by an id property in collection;
		 * 
		 * All objects in collection should have an unique id property
		 */
		public static function searchIndexInCollection(collection:IList, id:*, key:String='id'):int {
			var i:int;
			for( i = 0; i < collection.length; i++ ) {
				if( collection[i].hasOwnProperty(key) && collection[i][key] == id ) {
					return i;
				}
			}
			return -1;
		}

		/**
		 * Get all children of container and sub-containers who id property starts with 'startId'
		 * 
		 * @param startId String Starts id with
		 * @param container Container Root container for search of
		 */ 		
		static public function getChildByPrefixField( prefixField:String, container:DisplayObjectContainer ):Array {
			var result: Array = new Array();
			var index:int;
			
			for( index = 0; index < container.numChildren; index++ ) {
				var child:Object = container.getChildAt( index );
				if( child.hasOwnProperty( 'id' ) ) {
					if( String(child.id).substr( 0, prefixField.length ) == prefixField ) {
						result.push( child )
					} 
				}
				if ( child is DisplayObjectContainer ) {
					var listMoreChildren: Array = Util.getChildByPrefixField( prefixField, DisplayObjectContainer(child) )
					for each ( var moreChild: Object in listMoreChildren ) {
						result.push( moreChild )
					}
				}
			}
			return result;
		}
		
		static public function fillObjectVOFromField( objectVO:Object, container:DisplayObjectContainer, prefixField: String = "f_" ): void {
			var item: Object;
			var listChildren: Array = Util.getChildByPrefixField( prefixField, container );
			for each ( var child: Object in listChildren ) {
				
				var property: String = String(child.id).substr( prefixField.length );
				property = Util.cammelCaseToUnderScore( property );
				
				if( objectVO.hasOwnProperty( property ) ) {
					
					if( child.hasOwnProperty( "selectedDate" ) ) {
						if( child.selectedDate ) {
							objectVO[property] = child.selectedDate;
						}
					} else if( child.hasOwnProperty( "selectedItem" ) ) {
						if( child.selectedItem ) {
							objectVO[property] = child.selectedItem;
						}
					} else if( child.hasOwnProperty( "text" ) ) {
						if( String(child.text).length > 0 ) {
							if( objectVO[property] is Number ) {
								objectVO[property] = Util.parseStringToNumber(child.text);
							} else {
								objectVO[property] = String(child.text);
							}
						}
					} else if( child.hasOwnProperty( "selected" ) ) {
						if( objectVO.hasOwnProperty( property ) ) {
							objectVO[property] = child.selected;
						}
					}
					
				} else if( objectVO.hasOwnProperty( property+"_id" ) ) {
					if( child.hasOwnProperty( "selectedItem" ) ) {
						item = child.selectedItem
						if( item ) {
							if( item.hasOwnProperty( 'id' ) ) {
								objectVO[property+"_id"] = item.id;
							}
						}
					}
				} else {
					trace( 'No objeto VO nao foi encontrado propriedade para armazenar o campo ' + child.id );
				}
			}
		}

		/**
		 * Prenche os campos de um forma a partir dos campos de um objeto VO
		 * 
		 * O objeto VO deve estar na nomenclatura com underscor (ex: status_investimento)
		 * enquanto que a propriedade ID do field deve ter o prefix mais o nome do field na nomenclatura
		 * cammel case (ex: f_StatusInvestimento onde f_ é o prefix)
		 * 
		 * Uma outra nomenclatura para a propriedade poderá ser usada somente para campos textos (fields
		 * que contenham a propriedade text). Essa nomenclatura consiste na navegação de objetos
		 * com separação _T_. Ex f_Status_T_Nome é o mesmo que status.nome. Ou seja, a propriedade
		 * text do do campo f_Status_T_Nome será configurada com o valor de status.nome do objectVO.
		 * 
		 * Para evitar duplicação de nomes no campo ID, podemos usar no final do campo o prefixo _I
		 * e preencher com algum caracter apos o _I para que o campo id nao seja igual a outro campo.
		 * 
		 * Para forçar o uso de um formato específico use _F e em seguida o nome do formato que pode
		 * ser os seguintes valores:
		 * DATE - Formato em data
		 * DATELONG - Formato usando data longa
		 */
		public static function fillFieldFromObjectVO( objectVO:Object, container:DisplayObjectContainer, prefixField: String = "f_"): void {
			var listChildren:Array = Util.getChildByPrefixField( prefixField, container );
			for each ( var child:Object in listChildren ) {
				var property:String = String(child.id).substr( prefixField.length );
				
				// Verifica se existe o _I, eliminar todos os caracterer depois desse prefixo
				var indexI:int = property.indexOf( '_I' );
				if( indexI >= 0 ) {
					property = property.substr( 0, indexI );
				}
				
				// Verifica se existe um formato definido
				var format:String = "STRING";
				var indexF:int = property.indexOf( '_F' );
				if( indexF >= 0 ) {
					format = property.substr( indexF+2 ).toUpperCase();
					property = property.substr( 0, indexF );
				}
				
				var valueVO:Object = null;
				
				// Verifica se deve ser navegar como object text - string _T_ de separacao entre
				// objetos e propriedade.  status_T_nome = status.nome
				var listProperty:Array = property.split( '_T_' );
				var obj:Object = objectVO
				for each ( property in listProperty ) {
					property = Util.cammelCaseToUnderScore( property );
					if( obj.hasOwnProperty( property ) ) {
						obj = obj[property];
						valueVO = obj;
						if( obj == null ) {
							break;
						}
					}
				}
										
				if( valueVO ) {
					// Verifica se a propriedade do objectVO e um objeto com campo id
					// isso quer dizer que o field deve ter um dataProvider e devemos
					// configurar o selectedItem do mesmo id desse dataProvider
					// Nao da para igualar o selectedItem com o objectVO porque as instancias
					// sao diferentes - o teste para saber se e o mesmo objeto deve ser
					// pelo id
					if( child.hasOwnProperty( 'dataProvider' ) && child.hasOwnProperty('selectedItem') ) {
						if( valueVO ) {
							if( valueVO.hasOwnProperty( 'id' ) ) {
								var id:int = valueVO['id'];
								child.selectedItem = Util.searchObjectIdInCollection( child.dataProvider, id )
							}
						} else {
							child.selectedIndex = -1;
						}
						
					} else if( child.hasOwnProperty( "selectedDate" ) ) {
						if( valueVO is Date ) {
							child.selectedDate = valueVO;
						}
						
					} else if( child.hasOwnProperty( "text" ) ) {
						switch( format ) {
							case 'DATE':
								if( valueVO is Date ) {
									child.text = Util.dateTimeFormatter(valueVO as Date);
								}
								break;
							case 'DATETIME':
								if( valueVO is Date ) {
									child.text = Util.dateTimeFormatter(valueVO as Date);
								}
								break;
							case 'DATELONG':
								if( valueVO is Date ) {
									child.text = Util.dateTimeLongFormatter(valueVO as Date);
								}
								break;
							case 'INTEGER':
								if( valueVO is Number ) {
									child.text = Util.integerFormatter(Util.parseStringUSToNumber(valueVO.toString()));
								}
								break;
							case 'BOOLEAN':
								if( valueVO ) {
									child.text = "Sim";
								} else {
									child.text = "Não";
								}
								break;
							default:
								if( valueVO is Number ) {
									if( isNaN(Number(valueVO)) ) {
										child.text = "";
									} else {
										child.text = Util.numberFormatter(Util.parseStringUSToNumber(valueVO.toString()));
									}
								} else {
									child.text = valueVO;
								}
								break;
						}
						
					} else if( child.hasOwnProperty( "selected" ) ) {
						child.selected = valueVO;
					}
					
				} else {
					if( child.hasOwnProperty( "text" ) ) {
						child.text = null;
					}
				}
			}
		}
		
		static public function resetFields( container:DisplayObjectContainer, prop: Array = null, prefixField: String = "f_" ): void {
			if( ! prop ) {
				prop = new Array();
				prop.push( {property: 'text', value: null} )
				prop.push( {property: 'selectedIndex', value: -1} )
				//prop.push( {property: 'selectedItem', value: null} )
				prop.push( {property: 'selectedDate', value: null} )
				prop.push( {property: 'selected', value: false} )
				prop.push( {property: 'errorString', value: ''} )
			}
			var listChildren: Array = Util.getChildByPrefixField( prefixField, container );
			for each ( var child: Object in listChildren ) {
				for each( var o: Object in prop ) {
					if( child.hasOwnProperty( o.property ) ) {
						var value: Object = o.value;
						
						// Issue #243
						if( child is DateField ) {
							if( o.property == "text" && o.value == null ) {
								value = "";
							}
						}
						
						child[o.property] = value
					}
				}
			}
		}

		
		public static function getUniqueID():String {
			return UIDUtil.createUID()
		}
		
		/**
		 * Obtem o valor da propriedade de um objeto. O nome da propriedade
		 * poderá ser varios níveis separador por '.'.
		 * Exemplo: propertie = "grupo.nome" é o mesmo que obj['grupo']['nome']
		 */
		public static function getValuePropertieFromObj( obj:Object, propertie:String ):Object {
			var firstLevel:String;
			var posIndex:int = propertie.indexOf( '.' );
			if( posIndex >= 0 ) {
				firstLevel = propertie.substring( 0, posIndex );
				propertie = propertie.substring( posIndex + 1 );
			} else {
				firstLevel = propertie;
				propertie = null;
			}
			if( obj && obj.hasOwnProperty( firstLevel ) ) {
				if( propertie ) {
					return Util.getValuePropertieFromObj( obj[firstLevel], propertie );
				} else {
					return obj[firstLevel];
				}
			} else {
				return null;
			}
		}
		
		/**
		 * Show window component modal popup.
		 * 
		 * If you set under, this pop up will move position to under this component.
		 */ 
		public static function showPopUp( window: UIComponent, parent: DisplayObject, under: UIComponent = null, modal: Boolean = true, above: Boolean = false ): void {
			var e: Effect;
			
			PopUpManager.addPopUp( window, parent, modal );
			
			if( under ) {
				var heightComponent: int = under.height + under.getStyle( "borderThickness" ) + under.getStyle( "focusThickness" );
				var widthComponent: int = under.width + under.getStyle( "borderThickness" ) + under.getStyle( "focusThickness" );
				var point: Point = new Point( 0, heightComponent );
				point = under.localToGlobal( point );
				
				// Have space enought to show this component in bottom display
				// If not, put it below.				
				if (above || (point.y + window.height > under.screen.height &&
					point.y > window.height)) {
					point.y -= (heightComponent + window.height);
				}
				
				// Have space enought to show this component in right side
				// If not, put it left side.
				if (point.x + window.width > under.screen.width &&
					point.x > window.width) {
					point.x -= (window.width - widthComponent);
				}
				
				window.move( point.x, point.y );
				
				// Set effect to show
				//if( above ) {
				//	e = new WipeUp();
				//} else {
				//	e = new WipeDown();
				//}
				
				//e.duration = 500;
				//e.target = window;
				//e.end();
				//e.play();
				
			} else {
				PopUpManager.centerPopUp( window );
				
				// Set effect to show
				e = new Fade();
				e.duration = 500;
				e.target = window;
				e.end();
				e.play();
				
			}
		}
		
		public static function removePopUp( window: IFlexDisplayObject ): void {
			PopUpManager.removePopUp( window );
		}

		//--------------------------------------------------------------------------
		//
		//  Methods
		//
		//--------------------------------------------------------------------------
		
	}
}

